package com.medusa.aps.business.modules.demand.service.impl;

import cn.hutool.core.util.StrUtil;
import com.medusa.aps.business.model.constant.RedisConstants;
import com.medusa.aps.business.model.enums.SchedulingStatusEnum;
import com.medusa.aps.business.model.pagination.Page;
import com.medusa.aps.business.modules.basic.mp.entity.Material;
import com.medusa.aps.business.modules.basic.mp.service.MaterialService;
import com.medusa.aps.business.modules.demand.model.input.*;
import com.medusa.aps.business.modules.demand.model.output.ScheduleDetailOutSourcingModel;
import com.medusa.aps.business.modules.demand.model.output.ScheduleDetailSelfModel;
import com.medusa.aps.business.modules.demand.model.output.SchedulePageListModel;
import com.medusa.aps.business.modules.demand.model.output.ScheduleProcessDetailsVO;
import com.medusa.aps.business.modules.demand.mp.entity.OrderInformation;
import com.medusa.aps.business.modules.demand.mp.service.OrderInformationService;
import com.medusa.aps.business.modules.demand.service.ScheduleService;
import com.medusa.aps.business.modules.plan.mp.service.ProcessDetailsService;
import com.medusa.aps.business.modules.plan.mp.service.PurchasePlanService;
import com.medusa.aps.business.modules.plan.mp.service.SuggestedPlanService;
import com.medusa.aps.business.common.model.resp.SystemCode;
import com.medusa.aps.business.common.redis.annotation.Redisson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Set;

/**
 * @author miskw
 * @date 2023/12/27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ScheduleServiceImpl implements ScheduleService {
    private final OrderInformationService orderInformationService;
    private final MaterialService materialService;
    private final SuggestedPlanService suggestedPlanService;
    private final PurchasePlanService purchasePlanService;
    private final ProcessDetailsService processDetailsService;

    /**
     * 分页查询排程运算列表
     *
     * @param schedulePageQuery 分页参数
     * @return 分页结果
     */
    @Override
    public Page<SchedulePageListModel> schedulePage(SchedulePageQuery schedulePageQuery) {
        return orderInformationService.schedulePage(schedulePageQuery);
    }

    /**
     * 编辑排程订单
     *
     * @param orderParams 订单数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(value = RedisConstants.ORDER_LOCK_KEY, waitTime = 1)
    @Redisson(value = RedisConstants.MATERIAL_LOCK_KEY, waitTime = 1)
    @Redisson(value = RedisConstants.CUSTOMER_INFORMATION_LOCK_KEY, waitTime = 1)
    public void updateScheduleOrders(OrderParam orderParams) {
        orderInformationService.updateScheduleOrders(orderParams);
    }

    @Override
    @Redisson(value = RedisConstants.ORDER_LOCK_KEY, waitTime = 1)
    @Redisson(value = RedisConstants.MATERIAL_LOCK_KEY, waitTime = 1)
    @Redisson(value = RedisConstants.CUSTOMER_INFORMATION_LOCK_KEY, waitTime = 1)
    public void updateIncrementScheduleOrder(OrderIncrementParam orderIncrement) {
        orderInformationService.updateIncrementScheduleOrder(orderIncrement);
    }

    /**
     * 删除排程订单
     *
     * @param ids 订单id集合
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(value = RedisConstants.ORDER_LOCK_KEY, waitTime = 1)
    public void removeScheduleOrders(Set<Long> ids) {
        orderInformationService.removeScheduleOrders(ids);
    }

    /**
     * 释放占用物料
     *
     * @param id 订单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Redisson(value = RedisConstants.ORDER_LOCK_KEY, waitTime = 1)
    public BigDecimal releaseOccupationMaterial(Integer id) {
        OrderInformation orderInformation = orderInformationService.lambdaQuery()
                .select(OrderInformation::getId, OrderInformation::getOrderNumber,
                        OrderInformation::getMaterialId, OrderInformation::getItemCode,
                        OrderInformation::getSchedulingStatus, OrderInformation::getPlannedQuantity)
                .eq(OrderInformation::getId, id)
                .oneOpt()
                .orElseThrow(() -> {
                    throw SystemCode.DATA_NOT_EXIST.msgEx("订单数据不存在");
                });
        if (orderInformation.getSchedulingStatus() != SchedulingStatusEnum.CLOSE) {
            throw SystemCode.PARAM_VALID_ERROR.msgEx("只能释放无需生产订单");
        }
        Material material = materialService.lambdaQuery()
                .select(Material::getId, Material::getActualInventory, Material::getMaterialCode)
                .eq(Material::getId, orderInformation.getMaterialId())
                .oneOpt()
                .orElseThrow(() -> {
                    throw SystemCode.DATA_NOT_EXIST.msgEx(StrUtil.format("物料编码:{},数据不存在", orderInformation.getItemCode()));
                });

        orderInformationService.lambdaUpdate()
                .eq(OrderInformation::getId, orderInformation.getId())
                .set(OrderInformation::getSchedulingStatus, SchedulingStatusEnum.NOTARRANGED)
                .update();

        materialService.lambdaUpdate()
                .eq(Material::getId, material.getId())
                .set(Material::getActualInventory, material.getActualInventory().add(orderInformation.getPlannedQuantity()))
                .update();
        return orderInformation.getPlannedQuantity();
    }

    /**
     * 排程明细-自制生产
     *
     * @param controlDetailParam 排程明细接收参数
     * @return 分页结果
     */
    @Override
    public Page<ScheduleDetailSelfModel> selfControl(ControlDetailParam controlDetailParam, Page<ScheduleDetailSelfModel> page) {
        return suggestedPlanService.selfControl(controlDetailParam, page);
    }

    /**
     * 排程明细-外购/委外生产
     *
     * @param controlDetailParam 排程明细接收参数
     * @return 分页结果
     */
    @Override
    public Page<ScheduleDetailOutSourcingModel> unSelfControl(ControlDetailParam controlDetailParam, Page<ScheduleDetailOutSourcingModel> page) {
        return purchasePlanService.unSelfControl(controlDetailParam, page);
    }

    /**
     * 排程明细-工序明细
     *
     * @param scheduleProcessDetailsParam 参数
     * @return 结果
     */
    @Override
    public Page<ScheduleProcessDetailsVO> scheduleProcessDetail(ScheduleProcessDetailsParam scheduleProcessDetailsParam) {
        return processDetailsService.scheduleProcessDetail(scheduleProcessDetailsParam);
    }
}
